package Checkers; 
 
import java.util.*;


/**
 * This class should remain static
 */
public class ValidMoves {
    
    public static LinkedList<Move> getMoves( Board board ) {
                
        int ourSide = board.getPlayer();        
        LinkedList<Move> validMoves = new LinkedList<Move>();
        boolean mustJump = false;
        
        
        ArrayList<Coord> myPositions = updateMyPositions( board );
            
        for( int i = 0; i < myPositions.size(); ++i ) {
            
            Coord currentPos = myPositions.get(i);
            boolean isKing = board.getPieceAt(currentPos) == (ourSide + 3);
            ArrayList<Coord> adjacentPositions = validAdjacentPositions(board, currentPos.x, currentPos.y, isKing, ourSide);
                        
                
            // For every adjacent position
            ListIterator<Coord> adjPosItor = adjacentPositions.listIterator(0);
            while( adjPosItor.hasNext() ) {
                
                Coord adjPos = adjPosItor.next();
                int adjPosPiece = board.getPieceAt(adjPos);
                
                if ( adjPosPiece == 0 && !mustJump ) {
                    
                    Move aMove = new Move(currentPos, adjPos);
                    validMoves.add(aMove);
                    continue;
                }
                
                // Need to check for possible jump
                if ( adjPosPiece != ourSide && adjPosPiece != (ourSide + 3) && adjPosPiece != 0 ) {
                                            
                    Coord jumpPos = jumpCoordinate(currentPos, adjPos);
                    if ( board.getPieceAt(jumpPos) == 0 ) {
                        // Confirmed jump
                            
                        Move jumpMove = new Move(currentPos, jumpPos);
                        ArrayList<Move> nextJumps = getJumps(board, jumpMove, isKing);
                        
                        if ( !mustJump ) {
                            
                            validMoves.clear();
                            mustJump = true;
                        }
                        if ( nextJumps.size() > 0 ) {
                            
                            validMoves.addAll(nextJumps);
                        }
                        else {
                            validMoves.add(jumpMove);
                        }
                    }
                }                   
            }
        }
        
        return validMoves;
    }
    
    
    
    private static ArrayList<Coord> updateMyPositions( Board board ) {
        
        ArrayList<Coord> myPositions = new ArrayList<Coord>(12);
        int ourSide = board.getPlayer();
        
        // If we're red, start from the top
        if (ourSide == 1) {
            int col = 0;
            byte piece = 0;
            for (int row = 0 ; row < 8; row++) {
                if (row % 2 == 0)   col = 1;
                else                col = 0;
                for (; col < 8; col+=2) {
                    piece = board.getPieceAt(row, col);
                    if (piece == ourSide || piece == ourSide + 3)
                        myPositions.add(new Coord(row, col));
                    if (myPositions.size() == 12) break;
                }
            }
        } 
        // We're black, start from the bottom
        else {
            int col = 0;
            byte piece = 0;
            for (int row = 7; row >= 0; row--) {
                if (row % 2 == 1)   col = 0;
                else                col = 1;
                for (; col < 8; col+=2) {
                    piece = board.getPieceAt(row, col);
                    if (piece == ourSide || piece == ourSide + 3)
                        myPositions.add(new Coord(row, col));
                    if (myPositions.size() == 12) break;
                }
            }
            
        }
        
        return myPositions;
    }
    
    
    
    private static ArrayList<Move> getJumps(Board board, Move prevJump, boolean isKing ) {
        
        ArrayList<Move> jumps = new ArrayList<Move>(2); 
        int ourSide = board.getPlayer();
        Coord currentPos = prevJump.end();
                
        ArrayList<Coord> adjacentPositions = validAdjacentPositions(board, currentPos.x, currentPos.y, isKing, ourSide);
        
        
        // For every adjacent position
        ListIterator<Coord> adjPosItor = adjacentPositions.listIterator(0);
        while ( adjPosItor.hasNext() ) {
            
            Coord adjPos = adjPosItor.next();
                                
            int adjPosPiece = board.getPieceAt(adjPos);
            
            Coord jumpPos = jumpCoordinate(currentPos, adjPos);
            // Need to check for possible jump
            if ( adjPosPiece != ourSide && adjPosPiece != (ourSide + 3) && adjPosPiece != 0 
            		&& !prevJump.coordExists( jumpPos ) ) {
            
           
                if ( board.getPieceAt(jumpPos) == 0 ) {
                    
                    // Confirmed jump
                	Move j = prevJump.getCopy();
                	j.addCoord( jumpPos );
                    jumps.add( j );
                }
            }           
        }
        
        
        ArrayList<Move> allJumps = new ArrayList<Move>();
        for ( int i = 0; i < jumps.size(); ++i ) {
        	
        	allJumps.addAll( getJumps(board, jumps.get(i), isKing) );
        }
       /* if ( jumps.size() >= 1 ) {
            
            allJumps = joinJumps( jumps.get(0), getJumps(board, jumps.get(0), isKing) );
        }
        if ( jumps.size() == 2 ) {
            
            allJumps.addAll( joinJumps( jumps.get(1), getJumps(board, jumps.get(1), isKing)));
        }
        */
        if ( allJumps.size() > 0 ) {
            
            return allJumps;
        }
        else {
            return jumps;
        }
    }
    
    
    
    private static ArrayList<Move> joinJumps( Move jump, ArrayList<Move> jumpsToJoin) {
        
        ArrayList<Move> joinedJumps = new ArrayList<Move>();
        
        int index = 0;
        ListIterator<Move> li = jumpsToJoin.listIterator(0);
        
        while ( li.hasNext() ) {
            
            Move aMove = li.next();
            
            joinedJumps.add(index, jump.getCopy());
            
            for (int i = 1; i < aMove.n; ++i) {
                
                joinedJumps.get(index).addCoord(aMove.moves[i]);
            }
            
            ++index;
        }
        
        
        return joinedJumps;
    }
    
    
    
    private static ArrayList<Coord> validAdjacentPositions(Board board, int x, int y, boolean king, int side){
        
        Coord[] positions = board.getAdjacentTo(x,y);
        if (king) {
            ArrayList<Coord> validPositions = new ArrayList<Coord>(4);
            for(int i = 0; i < positions.length; ++i){
                
                validPositions.add(positions[i]);
            }
            
            return validPositions;
        }
        
        ArrayList<Coord> validPositions = new ArrayList<Coord>(2);
        for(int i = 0; i < positions.length; ++i) {
            
            Coord adjPos = positions[i];
            if (side == 1){
                
                if ( adjPos.x > x ) {
                    
                    validPositions.add(adjPos);
                }
            }
            else {
                
                if (adjPos.x < x) {
                    
                    validPositions.add(adjPos);
                }
            }
        }
        
        return validPositions;
    }
    
    
    
    private static Coord jumpCoordinate(Coord current, Coord adj ) {
        return new Coord(adj.x + (adj.x - current.x), adj.y + (adj.y - current.y));
    }
    
    
    public static void output(Board b)
    {
        LinkedList<Move> allMoves = getMoves(b);

        if (allMoves.size()==0)
        {
            System.out.println("No Valid Moves Found.");
            System.out.println("---- G A M E   O V E R ----");
        }
        else
            System.out.println("Valid Moves for Player "+b.getPlayer()+":");

        for(int i=0;i<allMoves.size();i++)
        {
            System.out.println(allMoves.get(i));
        }
//        System.out.println("Nothx");
    }
    
    public static boolean isValid(Move m, Board b)
    {
        
        LinkedList<Move> allMoves = getMoves(b);
        for (int i=0;i<allMoves.size();i++)
            if(allMoves.get(i).equals(m))
                return true;
      
        return false;
    }
    /*
    public static void main(String[] argv) {
        
        Board b = new Board();
        b.printBoard();
        
        LinkedList<Move> moves = getMoves(b);
        
        ListIterator<Move> li = moves.listIterator(0);
        while( li.hasNext() ) {
            
            Move aMove = li.next();
            System.out.println("Move: From " + aMove.start().x + "," + aMove.start().y + " to " + aMove.end().x + "," + aMove.end().y);
        }
    }*/
}

